package com.zxl.readsms

import android.accessibilityservice.AccessibilityService
import android.annotation.SuppressLint
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.database.Cursor
import android.graphics.Color
import android.net.Uri
import android.os.Build
import android.os.Handler
import android.os.Message
import android.telephony.TelephonyManager
import android.util.Log
import android.view.accessibility.AccessibilityEvent
import androidx.core.app.NotificationCompat
import com.zxl.readsms.mail.Mail
import com.zxl.readsms.mail.MailSender
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.FormBody
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.json.JSONObject
import java.net.URLEncoder
import java.text.SimpleDateFormat
import java.util.Date
import java.util.regex.Pattern
import android.util.Base64

class DemoService : AccessibilityService() {
    private var phoneNumber :String? =""
    private var giteeToken =""
    private val sdf = SimpleDateFormat("MM-dd HH:mm:ss")
    private lateinit var sp: SharedPreferences
    private val mHandler: Handler = object : Handler() {
        override fun handleMessage(msg: Message) {
            when (msg.what) {
                MSG_INBOX -> setSmsCode(msg.obj as String)
            }
        }
    }
    private val mail = Mail().apply {
        mailServerHost = MAIL_SERVER_HOST
        mailServerPort = MAIL_SERVER_PORT
        fromAddress = MAIL_FROM_ADDRESS
        password = MAIL_PASSWORD
        toAddress = arrayListOf(MAIL_TO_ADDRESS)

    }

    private fun registerBroadcast() {
        Log.d("zxl",  "开启无障碍服务成功，注册监听广播")
        smsContentObserver = SMSContentObserver( mHandler)
        contentResolver.registerContentObserver(
            Uri.parse("content://sms/"), true, smsContentObserver!!
        ) // 注册监听短信数据库的变化
    }
    override fun onServiceConnected() {
        super.onServiceConnected()
        registerBroadcast()
    }
    override fun onAccessibilityEvent(p0: AccessibilityEvent?) {}

    override fun onInterrupt() {}

    //服务创建时
    override fun onCreate() {
        super.onCreate()
        sp=getSharedPreferences(SP_NAME, MODE_PRIVATE)
        getPhoneNum()
        //服务创建时创建前台通知
        val notification = createForegroundNotification()
        //启动前台服务
        startForeground(1, notification)
        PUSH_TYPE = sp.getInt("PUSH_TYPE",2)
        PUSH_TO_WX_TOPIC = sp.getBoolean("PUSH_TO_WX_TOPIC",false)

    }
    @SuppressLint("MissingPermission")
    private fun getPhoneNum() {
        val tm = this.getSystemService(TELEPHONY_SERVICE) as TelephonyManager
        phoneNumber = tm.line1Number //手机号码
        if (!phoneNumber.isNullOrEmpty()) {
            phoneNumber = phoneNumber!!.replace("+", "")
            if (phoneNumber!!.startsWith("86")) {
                phoneNumber = phoneNumber!!.substring(2)
            }
        }
    }

    //服务销毁时
    override fun onDestroy() {
        //在服务被销毁时，关闭前台服务
        stopForeground(true)
        super.onDestroy()
        smsContentObserver?.run {
            contentResolver.unregisterContentObserver(this) // 取消监听短信数据库的变化
        }

    }

    //创建前台通知，可写成方法体，也可单独写成一个类
    private fun createForegroundNotification(): Notification {
        //前台通知的id名，任意
        val channelId = "ForegroundService"
        //前台通知的名称，任意
        val channelName = "Service"
        //发送通知的等级，此处为高，根据业务情况而定
        val importance = NotificationManager.IMPORTANCE_HIGH
        //判断Android版本，不同的Android版本请求不一样，以下代码为官方写法
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(channelId, channelName, importance)
            channel.lightColor = Color.BLUE
            channel.lockscreenVisibility=Notification.VISIBILITY_PRIVATE
            val notificationManager =
                getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            notificationManager.createNotificationChannel(channel)
        }

        //点击通知时可进入的Activity
        val notificationIntent = Intent(this, SmsAct::class.java)
        val pendingIntent = if (Build.VERSION.SDK_INT>=31){
            PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_MUTABLE)
        }else{
            PendingIntent.getActivity(this, 0, notificationIntent, 0)
        }

        //最终创建的通知，以下代码为官方写法
        //注释部分是可扩展的参数，根据自己的功能需求添加
        return NotificationCompat.Builder(this, channelId)
            .setContentTitle("百通经贸")
            .setContentText("勇敢牛牛，不怕困难")
            .setSmallIcon(R.mipmap.ic_launcher) //通知显示的图标
            .setContentIntent(pendingIntent) //点击通知进入Activity
            .setTicker("提示语")
            .build()
    }


    private var smsContentObserver: SMSContentObserver? = null
    private val client = OkHttpClient()

    @SuppressLint("Range")
    private fun setSmsCode(_id: String) {
        var cursor: Cursor? = null
        try {
            cursor = contentResolver.query(
                Uri.parse("content://sms/inbox"),
                arrayOf("_id", "address", "read", "body", "date", "status", "type"),
                "_id = $_id",
                null,
                null
            )
            if (cursor != null){
                while (cursor.moveToNext()){
                    val id = cursor.getString(0)
                    val address = cursor.getString(1)
                    val read = cursor.getString(2)
                    val body = cursor.getString(3) // 在这里获取短信信息
                    val smsdate = cursor.getLong(4)
                    val status = cursor.getInt(5)
                    val type = cursor.getInt(6)
                    if (body.startsWith("【工单达到提醒】")||body.startsWith("【工单到达提醒】")||body.startsWith("【预超时提醒】")){
                        sb.clear()
                        return
                    }
                    log("${phoneNumber} 最后短信：${sdf.format(Date(smsdate))}")
                    log("id=$id  address=$address  read=$read  status=$status  type=$type")
                    log("$body")
                    // 如果当前时间和短信时间间隔超过10秒,认为这条短信无效
                    val nowdate = System.currentTimeMillis()
                    if (nowdate - smsdate > 10 * 1000) {
                        log("**>10S**")
                    }
                    if (status==-1){//接收的短信
                        sendGet(body,address,smsdate)
                    }else{
                        sendLog2Wx("**不是收信**丢")
                    }
                }
            }else{
                sendLog2Wx("**查询不到该id短信")
            }
        } catch (e: Exception) {
            sendLog2Wx("**短信异常${e.message}")
            e.printStackTrace()
        }finally {
            cursor?.close()
        }
    }


    private fun sendGet(smsContent: String,address:String,date:Long) {
        log(  "--推送--" )
        if (phoneNumber.isNullOrEmpty()) getPhoneNum()
        var needSend=smsContent.contains("验证码")
        var code=""
        if (needSend){
            code=matchCode(smsContent)
            log( "验证码$code" )
        }
        needSend=!code.isNullOrEmpty()
        val newContent=getPushText(smsContent,address,date,code)
        if (!needSend){
            sendLog2Wx(  "==无码不推" )
            return
        }
       GlobalScope.launch {
           withContext(Dispatchers.IO){
           when(PUSH_TYPE){
               2 -> {
                   mail.apply {
                       subject =  "【验证码】$code"
                       content = newContent
                       ccAddress = MAIL_CC_ADDRESS
                   }
                   val sb2=StringBuilder(sb.toString())
                   sendLog2Wx(  "==邮件推送验证码" )
                   MailSender.getInstance().sendMail(mail,object :MailSender.OnMailSendListener{
                       override fun onError(e: Throwable) {
                           e.printStackTrace()
                           sb2.append(e.message)
                           val cc=getPushText(smsContent,address,date,code,true)
                           sendError2Gitee(cc,sb2)
                       }
                       override fun onSuccess() {}
                   })
               }
               else -> {
                   log(  "微信推送" )
                   //发送给订阅号
                   if (PUSH_TO_WX_TOPIC){
                       sendLog2Wx(  "==推给所有人" )
                       val c = URLEncoder.encode(newContent, "utf-8")
                       val url = "http://wxpusher.zjiecode.com/api/send/message/?appToken=$APPTOKEN&content=$c&topicId=$MSG_TOPIC_ID"
                       requestUrl(url)
                   }
               }
            }
           }
       }
    }

    private fun sendLog2Wx(msg:String) {
        GlobalScope.launch {
            withContext(Dispatchers.IO){
                if (!msg.isNullOrEmpty()) log(msg)
                val c = URLEncoder.encode(sb.toString(), "utf-8")
                val url = "http://wxpusher.zjiecode.com/api/send/message/?appToken=$APPTOKEN&content=$c&uid=$UID_ZXL"
                requestUrl(url)
                sb.clear()
            }
        }
    }

    private fun requestUrl(url: String, map: Map<String, String>? = null): Response {
        val requestBuilder: Request.Builder = Request.Builder().url(url)
        var request: Request = if (!map.isNullOrEmpty()) {
            val builder = FormBody.Builder()
            map.keys.forEach {
                builder.add(it, map[it].toString())
            }
            val requestBody = builder.build()
            requestBuilder.post(requestBody).build()
        } else {
            requestBuilder.build()
        }
        return client.newCall(request).execute()
    }

    private fun getPushText(body: String,address:String,date:Long,code:String,forceUseNomal:Boolean =false) : String {
        val time=sdf.format(Date(date))
        val cc="${if (code.isNullOrEmpty()) "" else "验证码：$code\n"}发件人：$address\n${if (phoneNumber.isNullOrEmpty()) "" else "机主：$phoneNumber\n"}时间：$time\n内容：$body"
        if (forceUseNomal) return cc
        return when(PUSH_TYPE){
            2->{
                """
                <div class="playground" style="box-sizing: border-box;">
                    <div class="card-placeholder" style="position: fixed;display: inline-block;background: #ddd;">
                    </div>
                
                    <div class="card" style="display: inline-block;float: left;background: #fff;width: 250px;box-shadow: 0 0 2px 0 rgba(0, 0, 0, .15), 0 0 4px 0 rgba(0, 0, 0, .2), 0 12px 12px 0 rgba(0, 0, 0, .15);margin: 0.5rem 1rem;transition: box-shadow .2s ease-in-out;border-radius: 15px;overflow: hidden;">
                
                        <div class="card-head" style="background: #eee;padding: 2.5rem 1rem;text-align: left;font-family: Menlo, " Courier New";position: relative;">
                            <span class="name">$body</span>
                        </div>
                
                        <div class="card-text" style="padding: 0.75rem;">
                            <h3 style="margin: 0 0 0.25rem 0;font-size: 1rem;line-height: 1.5rem;font-weight: 600;transition: color .2s ease-in-out;">${if (code.isNullOrEmpty()) "" else "$code"}</h3>
                            <span style="margin: 0;font-size: 0.8125rem;line-height: 1rem;font-weight: 200;">发件人：$address</span>
                            <br />
                            <span style="margin: 0;font-size: 0.8125rem;line-height: 1rem;font-weight: 200;">时间：$time</span>
                            <br />
                            <span style="margin: 0;font-size: 0.8125rem;line-height: 1rem;font-weight: 200;">${if (phoneNumber.isNullOrEmpty()) "" else "机主：$phoneNumber"}</span>
                        </div>
                    </div>
                </div>
                """.trimIndent()
            }
            else ->cc
        }
    }

    private fun matchCode(url: String): String {
        val pattern = "[0-9]{4,}"
        val r = Pattern.compile(pattern)
        val m = r.matcher(url)
        while (m.find()){
            return m.group(0)
        }
        return ""
    }

    /**********
     * 发送到gitee
     */
    private fun sendError2Gitee(newContent: String ,errStr:StringBuilder) {
        GlobalScope.launch {
            withContext(Dispatchers.IO){
                sendLog2Wx(  "==邮件推送异常，转为微信推送" )
                val c = URLEncoder.encode(newContent, "utf-8")
                val url = "http://wxpusher.zjiecode.com/api/send/message/?appToken=$APPTOKEN&content=$c&topicId=$MSG_TOPIC_ID"
                requestUrl(url)
                uploadFile(errStr)
            }
        }
    }

    private fun getToken(errStr:StringBuilder) {
        val tokenResult = requestUrl(
            "https://gitee.com/oauth/token", mapOf(
                "grant_type" to "password",
                "username" to "30784510@qq.com",
                "password" to "260213qq",
                "client_id" to "08518b00391e00874e1136512dc6e148179a94e305c51a4b4e7f60e23cf8d4e7",
                "client_secret" to "cd3b2fce618b0f26ad9b9a747b878baca39a0252cd98461569bcb87d07a8d6c5",
                "scope" to "projects gists"
            )
        )
        if (tokenResult.code==200){
            val job= JSONObject(tokenResult.body?.string())
            giteeToken= job["access_token"] as String
            uploadFile(errStr)
        }else{
            Log.e("zxl", "拿token异常$tokenResult" )
        }
    }

       private fun uploadFile(errStr:StringBuilder) {
           if (giteeToken != null) {
               val uploadResult = requestUrl(
                   "https://gitee.com/api/v5/repos/yue7/ZxlPub/contents/smsLog/${
                       sdf.format(
                           Date(
                               System.currentTimeMillis()
                           )
                       )
                   }.txt", mapOf(
                       "access_token" to giteeToken,
                       "content" to Base64.encodeToString(errStr.toString().toByteArray(), Base64.NO_WRAP),
                       "message" to if (phoneNumber.isNullOrEmpty()) "递交信息" else phoneNumber!!
                   )
               )
               if(uploadResult.code==401){
                   getToken(errStr)
               }else if (uploadResult.isSuccessful){
                   errStr.clear()
                   Log.e("zxl", "上传成功：$uploadResult" )
               }else{
                   Log.e("zxl", "上传出错结果：$uploadResult" )
               }
           }
       }

}